DynamoDBの scan() でフィルターを使って取得したデータが0件でも、続きのデータが存在するか確認してみた
DynamoDBテーブルでscan()
やquery()
を使うとき、フィルタを使うことがあります。
そこでふと気になりました。フィルタ適応後のデータが0件でも、続きはあるよね?と。
最初にまとめ
DynamoDBでscan()やquery()を使うとき、「続きのデータがある?(最後のデータ?)」の判断は、LastEvaluatedKey
を参照しましょう。データ件数で判断しないように注意です。
DynamoDBテーブルを準備する
以前に作成したDynamoDBテーブルを流用します。
scan()で調べてみる
1回のscan()
で最大1MBのデータを取得できますが、実際に用意するのは大変なので、Limit
を使って取得するデータ量を減らします。
まずは、Limit無しで試してみる
Limit
無しでtitleに「買う」が含まれているデータ取得できるか試してみます。
import boto3 from boto3.dynamodb.conditions import Attr def main(): dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('todo-tag-sample-table') options = { 'FilterExpression': Attr('title').contains('買う'), } res = table.scan(**options) if len(res.get('Items', [])) == 0: print('data is nothing.') else: print('data is exist.') data = res.get('Items', []) dump(data) if 'LastEvaluatedKey' not in res: print('LastEvaluatedKey is nothing.') else: print('LastEvaluatedKey is exist.') print(res['LastEvaluatedKey']) def dump(items): for item in items: print(item) if __name__ == '__main__': main()
タイトルに買う
が含まれているデータを取得できました。また、1回のscan()
で全データを取得できています(続きは無い)。
$ python get_no_limit.py data is exist. {'todoId': 't0001', 'tags': {'Amazon', '買い物', '単三'}, 'userId': 'u0001', 'title': '電池を買う'} {'todoId': 't0003', 'userId': 'u0001', 'tags': {'買い物', 'スーパー'}, 'title': 'ちくわを買う'} LastEvaluatedKey is nothing.
Limitをつけて、取得したデータが0件でも、続きがあるか試してみる
Limit
を指定して、続きのデータがあるか試してみます。
import boto3 from boto3.dynamodb.conditions import Attr def main(): dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('todo-tag-sample-table') options = { 'FilterExpression': Attr('title').contains('買う'), 'Limit': 1, } res = table.scan(**options) if len(res.get('Items', [])) == 0: print('data is nothing.') else: print('data is exist.') data = res.get('Items', []) dump(data) if 'LastEvaluatedKey' not in res: print('LastEvaluatedKey is nothing.') else: print('LastEvaluatedKey is exist.') print(res['LastEvaluatedKey']) def dump(items): for item in items: print(item) if __name__ == '__main__': main()
取得したデータは0件でしたが、LastEvaluatedKey
があるので、続きのデータが存在することがわかります。
$ python get_no_limit.py data is nothing. LastEvaluatedKey is exist. {'todoId': 't0005', 'userId': 'u1111'}
おまけ:Limitありで全データを取得する
最後のデータでない場合は、LastEvaluatedKey
が渡されるので、ループすると全データを取得できます。
import boto3 from boto3.dynamodb.conditions import Attr def main(): dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('todo-tag-sample-table') options = { 'FilterExpression': Attr('title').contains('買う'), 'Limit': 1, } data = [] while True: res = table.scan(**options) data += res.get('Items', []) if len(res.get('Items', [])) == 0: print('data is nothing.') else: print('data is exist.') data = res.get('Items', []) dump(data) if 'LastEvaluatedKey' not in res: print('LastEvaluatedKey is nothing.') else: print('LastEvaluatedKey is exist.') print(res['LastEvaluatedKey']) # 続きのデータが無ければ、取得ループを抜ける if 'LastEvaluatedKey' not in res: break options['ExclusiveStartKey'] = res['LastEvaluatedKey'] def dump(items): for item in items: print(item) if __name__ == '__main__': main()
ループをすることで、全データの取得ができました。
$ python get_limit_all_data.py data is nothing. LastEvaluatedKey is exist. {'todoId': 't0005', 'userId': 'u1111'} data is nothing. LastEvaluatedKey is exist. {'todoId': 't0006', 'userId': 'u1111'} data is exist. {'todoId': 't0001', 'tags': {'Amazon', '単三', '買い物'}, 'userId': 'u0001', 'title': '電池を買う'} LastEvaluatedKey is exist. {'todoId': 't0001', 'userId': 'u0001'} data is nothing. LastEvaluatedKey is exist. {'todoId': 't0002', 'userId': 'u0001'} data is exist. {'todoId': 't0003', 'userId': 'u0001', 'tags': {'スーパー', '買い物'}, 'title': 'ちくわを買う'} LastEvaluatedKey is exist. {'todoId': 't0003', 'userId': 'u0001'} data is nothing. LastEvaluatedKey is exist. {'todoId': 't0004', 'userId': 'u0001'} data is nothing. LastEvaluatedKey is nothing.